from PyQt5.QtWidgets import (
    QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel,
    QTextEdit, QTreeWidget, QTreeWidgetItem, QListWidget, QListWidgetItem,
    QLineEdit, QSizePolicy, QGraphicsDropShadowEffect
)
from PyQt5.QtGui import QColor, QIcon, QFont, QIntValidator
from PyQt5.QtCore import Qt, QTimer
import os
import time
from emsContronl import ChargeDischargeController
from connection import WebSocketWorker
from data_processing import (
    update_device_tree,
    get_item_level,
    get_rtv_ids_for_item,
    update_data_list_by_ids
)
from datetime import datetime
from data_processing import DataProcessor
import gc
# 设置每小时自动更新token
from PyQt5.QtCore import QTimer
# 导入浏览器管理模块
# from browser_manager import get_browser_manager, init_browser_manager

class WebSocketClient(QMainWindow):
    """
    EMS监控系统界面模块
    包含主窗口类、界面组件初始化、事件处理等UI相关功能
    """

    def __init__(self):
        # 初始化父类
        super().__init__()
        # 首先初始化日志控件
        self.log_text = QTextEdit(self)
        self.log_text.setReadOnly(True)
        self.log_text.setStyleSheet("QTextEdit { background-color: #f0f0f0; font-size: 12px; color: #333; border: 1px solid rgba(128, 128, 128, 0.1); border-radius: 5px; }")
        # 调试日志：确认log_text已初始化
        print("log_text initialized successfully")
        # 初始化ws_worker
        self.ws_worker = None
        # 初始化device_info
        self.device_info = {}
        self.latest_rtv_data = {}

        # 初始化ChargeDischargeController，并传入log_callback参数
        self.controller = ChargeDischargeController(log_callback=self.log)

        # 初始化QTimer，并连接timeout信号到update_display槽函数
        self.update_timer = QTimer()
        self.update_timer.timeout.connect(self.update_display)
        # 移至initUI之后启动定时器

        self.setWindowIcon(QIcon("./img/ems.png"))
        # self.initUI()

        # 在UI初始化后启动定时器
        self.update_timer.start(3000)

        # 数据处理模块消息传递 - 只保留这一处初始化
        self.data_processor = DataProcessor()
        self.data_processor.db_log_signal.connect(self.log)

        # 初始化data_insert.py中的storage（带日志回调）
        from data_insert import init_storage
        init_storage(log_callback=self.log)

        # 初始化mysql_storage.py中的全局storage实例（带日志回调）
        from mysql_storage import init_storage as init_mysql_storage
        init_mysql_storage(log_callback=self.log)

        # 初始化token_input
        self.token_input = QLineEdit()

        # 智能token更新间隔调整机制
        self.token_update_interval_normal = 3600000  # 正常状态：1小时
        self.token_update_interval_fast = 60000      # 失效状态：1分钟
        self.is_token_invalid = False                # token失效状态标志
        self.last_token_check_time = 0               # 上次token检查时间
        self.token_recovery_check_count = 0          # token恢复检查计数
        self.max_recovery_checks = 3                 # 最大恢复检查次数
        self.last_external_token = ""                 # 上次读取的外部Token，用于变化检测

        self.token_timer = QTimer(self)
        self.token_timer.timeout.connect(self.update_token)
        self.token_timer.start(self.token_update_interval_normal)  # 初始使用正常间隔
        
        # 连接状态检查定时器 - 每30秒检查一次连接状态
        self.connection_check_timer = QTimer(self)
        self.connection_check_timer.timeout.connect(self.check_connection_recovery)
        self.connection_check_timer.start(30000)  # 30秒检查一次

        self.setWindowIcon(QIcon("./img/ems.png"))
        self.initUI()

        # 在UI初始化后创建数据处理器实例
        # self.data_processor = DataProcessor()
        # self.data_processor.db_log_signal.connect(self.log)

        # 初始化浏览器管理器
        # self.browser_manager = init_browser_manager(self.log)
        # self.log("浏览器管理器已初始化")
        
        # 可选：启动浏览器状态监控（每小时检查一次）
        # self.setup_browser_monitoring()

        # 在UI初始化后创建控制器实例
        self.controller = ChargeDischargeController(log_callback=self.log)

    def get_external_config_path(self):
        """
        获取外部config.ini文件路径
        支持打包环境和开发环境的动态路径解析
        """
        import sys

        # 获取当前执行文件的路径
        if getattr(sys, 'frozen', False):
            # 打包环境：exe文件在dist/getBYemsData_package目录下
            current_dir = os.path.dirname(sys.executable)
            self.log(f"[路径检测] 当前为打包环境，exe路径: {current_dir}")
        else:
            # 开发环境：使用当前文件路径
            current_dir = os.path.dirname(os.path.abspath(__file__))
            self.log(f"[路径检测] 当前为开发环境，脚本路径: {current_dir}")

        # 构建外部config.ini路径（上级目录的autoLoginLzhEms目录）
        parent_dir = os.path.dirname(current_dir)  # 上级目录
        config_path = os.path.join(parent_dir, "autoLoginLzhEms", "config.ini")

        self.log(f"[路径检测] 外部config.ini路径: {config_path}")

        # 检查文件是否存在
        if os.path.exists(config_path):
            self.log(f"[路径检测] ✓ 找到外部config.ini文件")
            return config_path
        else:
            self.log(f"[路径检测] ✗ 外部config.ini文件不存在: {config_path}")
            return None

    def update_token(self):
        """每小时更新一次token"""
        try:
            # 获取外部config.ini路径
            config_path = self.get_external_config_path()

            if not config_path:
                self.log(f"[定时更新] 无法找到外部config.ini文件，跳过token更新")
                self._mark_token_as_invalid()
                return

            from configparser import ConfigParser
            import os
            import tempfile
            import shutil
            
            config = ConfigParser()
            
            # 创建临时缓存文件路径
            temp_dir = tempfile.gettempdir()
            temp_config_path = os.path.join(temp_dir, "getBYemsData_external_config.ini")
            
            max_retries = 3
            retry_delay = 3  # 秒
            
            for attempt in range(max_retries):
                try:
                    # 快速复制外部配置文件到临时缓存
                    shutil.copy2(config_path, temp_config_path)
                    
                    # 从临时缓存文件读取配置
                    with open(temp_config_path, 'r', encoding='utf-8') as f:
                        config.read_file(f)
                    
                    # 读取成功后删除临时文件
                    try:
                        os.remove(temp_config_path)
                    except:
                        pass  # 忽略删除临时文件的错误
                        
                    self.log(f"[缓存复制] 成功复制外部配置到临时缓存并读取")
                    break  # 读取成功，跳出重试循环
                        
                except (IOError, OSError, PermissionError) as e:
                    # 清理临时文件
                    try:
                        if os.path.exists(temp_config_path):
                            os.remove(temp_config_path)
                    except:
                        pass
                        
                    if attempt < max_retries - 1:
                        self.log(f"[缓存复制] 第{attempt + 1}次复制文件失败，{retry_delay}秒后重试: {str(e)}")
                        time.sleep(retry_delay)
                    else:
                        self.log(f"[缓存复制] 文件复制失败，已达到最大重试次数: {str(e)}")
                        raise e

            url = config.get('websocket', 'url')
            token = url.split('?')[1] if '?' in url else ""

            if not token:
                self.log(f"[定时更新] 外部config.ini中未找到有效token，跳过更新")
                self._mark_token_as_invalid()
                return

            # 检查Token是否发生变化
            current_token = self.token_input.text().strip()
            if token == self.last_external_token and token == current_token:
                # Token没有变化，跳过更新操作
                self.log(f"[定时更新] Token无变化，跳过更新: {token[:20]}...")
                print(f"[定时更新] Token无变化，跳过更新: {token[:20]}...")
                return

            # 记录本次读取的外部Token
            self.last_external_token = token

            # 更新UI显示
            self.token_input.setText(token)
            self.log(f"[定时更新] Token已更新: {token}")
            print(f"[定时更新] Token已更新: {token}")

            # 将token写入本地config.ini，避免重复读取外部文件
            self._write_token_to_local_config(token)

            # 同步更新WebSocketWorker的token（仅在ws_worker已存在时更新）
            if hasattr(self, 'ws_worker') and self.ws_worker:
                self.ws_worker.token = token
                self.log(f"[参数更新] WebSocket Token已同步: {token}")
                print(f"[参数更新] WebSocket Token已同步: {token}")
            else:    
                # 启动时ws_worker还未创建，这是正常情况，无需警告
                self.log(f"[参数更新] WebSocket未启动，Token将在连接时使用")
                print(f"[参数更新] WebSocket未启动，Token将在连接时使用")

            # 检查token状态并调整更新间隔
            self._check_token_status_and_adjust_interval()

        except Exception as e:
            self.log(f"[定时更新] Token更新失败: {str(e)}")
            print(f"[定时更新] Token更新失败: {str(e)}")
            self._mark_token_as_invalid()
    
    def _check_token_status_and_adjust_interval(self):
        """检查token状态并调整更新间隔"""
        try:
            # 检查token是否有效
            token = self.token_input.text().strip()
            if not token:
                self._mark_token_as_invalid()
                return
            
            # 这里可以添加更复杂的token有效性检查逻辑
            # 目前简单检查token是否为空
            if token:
                # token有效，恢复正常更新间隔
                if self.is_token_invalid:
                    self.log("[Token状态] Token已恢复有效，恢复正常更新间隔")
                    self.token_timer.stop()
                    self.token_timer.start(self.token_update_interval_normal)
                    self.is_token_invalid = False
                    self.token_recovery_check_count = 0
            else:
                self._mark_token_as_invalid()
                
        except Exception as e:
            self.log(f"[Token状态] 检查token状态失败: {str(e)}")
            self._mark_token_as_invalid()
    
    def _mark_token_as_invalid(self):
        """标记token为失效状态并调整更新间隔"""
        if not self.is_token_invalid:
            self.log("[Token状态] Token失效，切换到快速更新模式")
            self.is_token_invalid = True
            self.token_timer.stop()
            self.token_timer.start(self.token_update_interval_fast)
            self.token_recovery_check_count = 0
            
            # token失效时触发程序重置
            self._reset_application()
    
    def _reset_application(self):
        """重置应用程序，清理连接和状态"""
        try:
            self.log("[程序重置] 开始重置应用程序状态...")
            
            # 停止WebSocket连接
            if hasattr(self, 'worker') and self.worker:
                self.worker.stop()
                self.log("[程序重置] WebSocket连接已停止")
            
            # 清理数据库连接（如果有）
            # 这里可以添加数据库连接清理逻辑
            
            # 重置相关状态
            if hasattr(self, 'worker'):
                self.worker = None
            
            # 重置token状态相关计数器
            self.token_recovery_check_count = 0
            self.last_token_check_time = 0
            
            self.log("[程序重置] 应用程序重置完成")
            
        except Exception as e:
            self.log(f"[程序重置] 重置过程中发生错误: {str(e)}")
    
    def check_connection_recovery(self):
        """检查连接状态是否恢复"""
        try:
            if not self.is_token_invalid:
                return  # 当前状态正常，无需检查
            
            # 检查WebSocket连接状态
            if hasattr(self, 'worker') and self.worker:
                # 检查连接状态标志
                is_connected = getattr(self.worker, 'is_connected', False)
                
                # 检查是否有活跃的数据流（通过最后消息时间判断）
                has_recent_activity = False
                if hasattr(self.worker, 'last_message_time'):
                    current_time = time.time()
                    last_message_time = getattr(self.worker, 'last_message_time', 0)
                    # 如果60秒内有消息，认为有活跃数据流
                    has_recent_activity = (current_time - last_message_time) < 60
                
                # 连接状态正常且有活跃数据流，认为连接已恢复
                if is_connected and has_recent_activity:
                    self.token_recovery_check_count += 1
                    self.log(f"[连接恢复] 连接状态检查 {self.token_recovery_check_count}/{self.max_recovery_checks}")
                    
                    # 连续多次检查连接正常，认为已恢复
                    if self.token_recovery_check_count >= self.max_recovery_checks:
                        self.log("[连接恢复] 连接状态已恢复，恢复正常更新间隔")
                        self.is_token_invalid = False
                        self.token_timer.stop()
                        self.token_timer.start(self.token_update_interval_normal)
                        self.token_recovery_check_count = 0
                        
                        # 连接恢复后，重新启动WebSocket连接
                        self._restart_websocket_connection()
                else:
                    # 连接状态不正常，重置恢复检查计数
                    self.token_recovery_check_count = 0
                    self.log("[连接恢复] 连接状态尚未恢复，继续快速更新模式")
            
        except Exception as e:
            self.log(f"[连接恢复] 检查连接状态失败: {str(e)}")
            self.token_recovery_check_count = 0
    
    def _restart_websocket_connection(self):
        """重启WebSocket连接"""
        try:
            self.log("[连接恢复] 正在重启WebSocket连接...")
            
            # 如果有worker实例，重新启动它
            if hasattr(self, 'worker') and self.worker:
                # 先停止当前连接
                self.worker.stop()
                
                # 等待一小段时间确保连接完全停止
                time.sleep(2)
                
                # 重新创建并启动worker
                token = self.token_input.text().strip()
                if token:
                    # 重新设置worker
                    self.worker = WebSocketWorker(token, self.rtv_interval)
                    self.worker.log_signal.connect(self.log)
                    self.worker.message_signal.connect(self.handle_websocket_message)
                    self.worker.connected_signal.connect(self.on_websocket_connected)
                    self.worker.disconnected_signal.connect(self.on_websocket_disconnected)
                    
                    # 设置浏览器实例（如果有）
                    if hasattr(self, 'browser') and self.browser:
                        self.worker.set_browser_instance(self.browser)
                    
                    # 设置SOC输入框引用
                    if hasattr(self, 'soc_input'):
                        self.worker.set_soc_input_reference(self.soc_input)
                    
                    # 启动worker
                    self.worker.start()
                    self.log("[连接恢复] WebSocket连接已重启")
                else:
                    self.log("[连接恢复] 无法重启WebSocket连接：token为空")
            
        except Exception as e:
            self.log(f"[连接恢复] 重启WebSocket连接失败: {str(e)}")

    def _read_token_from_local_config(self):
        """从本地config.ini读取token"""
        try:
            from configparser import ConfigParser
            import os
            
            # 获取本地config.ini路径
            local_config_path = os.path.join(os.path.dirname(__file__), 'config.ini')
            
            if not os.path.exists(local_config_path):
                return None
            
            config = ConfigParser()
            with open(local_config_path, 'r', encoding='utf-8') as f:
                config.read_file(f)
            
            # 获取websocket url
            if not config.has_section('websocket'):
                return None
                
            url = config.get('websocket', 'url', fallback='')
            if not url or '?' not in url:
                return None
            
            # 提取token
            token = url.split('?')[1]
            return token if token else None
            
        except Exception as e:
            self.log(f"[本地读取] 读取本地config.ini失败: {str(e)}")
            print(f"[本地读取] 读取本地config.ini失败: {str(e)}")
            return None

    def _write_token_to_local_config(self, token):
        """将token写入本地config.ini文件"""
        try:
            from configparser import ConfigParser
            import os
            
            # 获取本地config.ini路径
            local_config_path = os.path.join(os.path.dirname(__file__), 'config.ini')
            
            config = ConfigParser()
            
            # 如果文件存在，先读取现有配置
            if os.path.exists(local_config_path):
                with open(local_config_path, 'r', encoding='utf-8') as f:
                    config.read_file(f)
            
            # 确保有websocket节
            if not config.has_section('websocket'):
                config.add_section('websocket')
            
            # 更新token到url中，保持原有url结构
            current_url = config.get('websocket', 'url', fallback='ws://your-websocket-server-url')
            
            # 如果url中已有参数，替换；如果没有，添加
            if '?' in current_url:
                base_url = current_url.split('?')[0]
                new_url = f"{base_url}?{token}"
            else:
                new_url = f"{current_url}?{token}"
            
            config.set('websocket', 'url', new_url)
            
            # 写回文件
            with open(local_config_path, 'w', encoding='utf-8') as f:
                config.write(f)
            
            self.log(f"[本地缓存] Token已写入本地config.ini: {token}")
            print(f"[本地缓存] Token已写入本地config.ini: {token}")
            
        except Exception as e:
            self.log(f"[本地缓存] 写入本地config.ini失败: {str(e)}")
            print(f"[本地缓存] 写入本地config.ini失败: {str(e)}")    

    def initUI(self):
        """初始化界面布局和控件"""
        self.setWindowTitle('BY-EMS Monitoring System V1.0')
        self.setGeometry(100, 100, 700, 900)
        self.setStyleSheet("QMainWindow { background-color: #f0f0f0; padding: 5px; }")
        self.setGraphicsEffect(QGraphicsDropShadowEffect(blurRadius=2, xOffset=2, yOffset=2))

        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QHBoxLayout(central_widget)
        main_layout.setContentsMargins(0, 0, 0, 0)

        # 左侧控件布局
        left_panel = QWidget()
        left_layout = QVBoxLayout(left_panel)
        left_panel.setMaximumWidth(700)

        self.device_tree = QTreeWidget()
        self.device_tree.setHeaderLabels(['设备列表'])
        self.device_tree.setStyleSheet("QTreeWidget { font-size: 12px; }")
        self.device_tree.setStyleSheet(
            "QLineEdit { background-color:rgba(255, 255, 255, 0.9); border: 1px solid #ccc; border-radius: 3px; padding: 3px; color: #2196F3; }"
        )
        left_layout.addWidget(self.device_tree)

        # 中部监控设置区域
        settings_panel = QWidget()
        settings_layout = QVBoxLayout(settings_panel)
        settings_panel.setStyleSheet("background-color: #f0f0f0; border: 1px solid rgba(128, 128, 128, 0.1); padding: 10px;")

        # // 添加日志显示区域到布局
        left_layout.addWidget(self.log_text)

        # 定义一个函数，用于创建一个带有标签和输入框的行
        def styled_input(label_text, input_field):
            # 创建一个标签
            label = QLabel(label_text)
            # 设置标签的样式
            label.setStyleSheet("color: #2196F3; font-weight: bold;")
            # 设置输入框的宽度
            input_field.setFixedWidth(150)
            # 设置输入框的样式
            input_field.setStyleSheet("""
                QLineEdit {
                    background-color: rgba(255, 255, 255, 0.9);
                    border: 1px solid #ccc;
                    border-radius: 3px;
                    padding: 3px;
                    color: #2196F3;
                    margin: 0;
                }
                QLineEdit:focus {
                    border: 1px solid #2196F3;
                }
            """)
            # 创建一个水平布局
            row = QHBoxLayout()
            # 将标签和输入框添加到水平布局中
            row.addWidget(label)
            row.addWidget(input_field)
            # 创建一个QWidget，并将水平布局设置为它的布局
            row_widget = QWidget()
            row_widget.setLayout(row)
            # 返回QWidget
            return row_widget

        # 优先从本地config.ini读取token，如果没有有效token再从外部读取
        self.token_input = QLineEdit()
        token = self._read_token_from_local_config()
        
        if token:
            self.token_input.setText(token)
            self.log(f"[初始化] 成功从本地config.ini读取Token: {token}")
            print(f"[初始化] 成功从本地config.ini读取Token: {token}")
        else:
            # 本地没有有效token，尝试从外部config.ini读取
            config_path = self.get_external_config_path()
            if config_path:
                try:
                    from configparser import ConfigParser
                    config = ConfigParser()
                    # 使用with语句确保文件正确关闭，添加UTF-8编码支持
                    with open(config_path, 'r', encoding='utf-8') as f:
                        config.read_file(f)
                    url = config.get('websocket', 'url')
                    token = url.split('?')[1] if '?' in url else ""
                    self.token_input.setText(token)
                    self.log(f"[初始化] 成功从外部config.ini读取Token: {token}")
                    print(f"[初始化] 成功从外部config.ini读取Token: {token}")
                    
                    # 将外部token写入本地缓存
                    if token:
                        self._write_token_to_local_config(token)
                except Exception as e:
                    self.log(f"[初始化] 读取外部config.ini失败: {str(e)}")
                    print(f"[初始化] 读取外部config.ini失败: {str(e)}")
                    # 失败时创建空token输入框
                    self.token_input.setText("")
            else:
                self.log("[初始化] 未找到外部config.ini文件，创建空token输入框")
                print("[初始化] 未找到外部config.ini文件，创建空token输入框")
                self.token_input.setText("")

        # 设置每小时自动更新token
        from PyQt5.QtCore import QTimer
        self.token_timer = QTimer(self)
        self.token_timer.timeout.connect(self.update_token)
        self.token_timer.start(3600000)  # 3600000毫秒 = 1小时
        token_layout = QHBoxLayout()
        token_label = QLabel("Token:")
        token_label.setStyleSheet("color: #2196F3; font-weight: bold;")
        token_layout.addWidget(token_label)
        token_layout.addWidget(self.token_input)
        token_widget = QWidget()
        token_widget.setLayout(token_layout)
        settings_layout.addWidget(token_widget)

        self.charging_time_input_start = QLineEdit()
        self.charging_time_input_end = QLineEdit()
        self.discharging_time_input_start = QLineEdit()
        self.discharging_time_input_end = QLineEdit()
        self.charging_soc_input = QLineEdit()
        self.discharging_soc_input = QLineEdit()
        self.discharging_soc_input.setStyleSheet("""
            QLineEdit {
                padding: 1px;
                margin: 0;
                border: 1px solid #ccc;
                border-radius: 2px;
                min-height: 20px;
            }
            QLineEdit:focus {
                border: 1px solid #1e90ff;
            }
        """)
        # 新增间隔时间输入框
        self.interval_input = QLineEdit()
        self.interval_input.setValidator(QIntValidator(1, 3600))  # 1秒到1小时
        self.interval_input.setText("3")  # 默认3秒，表示使用系统默认值

        for box in [self.charging_time_input_start, self.charging_time_input_end,
                    self.discharging_time_input_start, self.discharging_time_input_end]:
            box.setValidator(QIntValidator(0, 23))

        # 配置重订阅间隔输入框（原充电SOC上限输入框）
        self.charging_soc_input.setValidator(QIntValidator(0, 10))  # 重订阅间隔时间(秒)，0-10秒
        self.charging_soc_input.setText("1")  # 默认值设为1秒（重订阅间隔）

        self.discharging_soc_input.setValidator(QIntValidator(0, 100))  # 保持放电SOC下限为百分比

        # 定义一个函数，用于创建一个包含两个标签和两个输入框的行
        def double_input_row(label1, input1, label2, input2):
            # 创建一个水平布局
            row = QHBoxLayout()
            # 设置第一个标签的样式
            label1.setStyleSheet("color: #2196F3; font-weight: bold;")
            # 设置第二个标签的样式
            label2.setStyleSheet("color: #2196F3; font-weight: bold;")
            input1.setFixedWidth(100)
            input2.setFixedWidth(100)
            input1.setStyleSheet("QLineEdit { background-color:rgba(255, 255, 255, 0.9); border: 1px solid #ccc; border-radius: 3px; padding: 3px; color: #2196F3; }")
            input2.setStyleSheet("QLineEdit { background-color:rgba(255, 255, 255, 0.9); border: 1px solid #ccc; border-radius: 3px; padding: 3px; color: #2196F3; }")
            row.addWidget(label1)
            row.addWidget(input1)
            row.addSpacing(30)
            row.addWidget(label2)
            row.addWidget(input2)
            row_widget = QWidget()
            row_widget.setLayout(row)
            return row_widget

        settings_layout.addWidget(double_input_row(QLabel("充电开始时间(HH):"), self.charging_time_input_start,
                                                  QLabel("充电结束时间(HH):"), self.charging_time_input_end))
        settings_layout.addWidget(double_input_row(QLabel("放电开始时间(HH):"), self.discharging_time_input_start,
                                                  QLabel("放电结束时间(HH):"), self.discharging_time_input_end))
        settings_layout.addWidget(double_input_row(QLabel("重订阅间隔(秒):"), self.charging_soc_input,
                                                  QLabel("放电SOC下限(%):"), self.discharging_soc_input))
        # 添加间隔时间输入框
        settings_layout.addWidget(styled_input("请求间隔时间(秒):", self.interval_input))

        # 保存间隔时间设置
        self.interval_input.textChanged.connect(self._update_interval)
        left_layout.addWidget(settings_panel)
        # 注释掉重复的日志窗口创建代码

        self.connect_btn = QPushButton("连接WebSocket")
        self.disconnect_btn = QPushButton("断开连接")
        self.refresh_btn = QPushButton("刷新数据")
        self.browser_status_btn = QPushButton("检查浏览器状态")
        self.recover_browser_btn = QPushButton("恢复浏览器")

        self.connect_btn.clicked.connect(self.start_websocket)
        self.disconnect_btn.clicked.connect(self.stop_websocket)
        self.refresh_btn.clicked.connect(self.refresh_data)
        self.browser_status_btn.clicked.connect(self.check_browser_status)
        self.recover_browser_btn.clicked.connect(self.recover_browser)

        self.recover_browser_btn.setEnabled(False)  # 默认禁用恢复按钮

        self.connect_btn.setStyleSheet("""
            QPushButton {
                background-color: #4CAF50;
                color: white;
                padding: 10px;
                border: none;
                border-radius: 5px;
            }
            QPushButton:hover { background-color: #45a049; }
            QPushButton:disabled { background-color: #cccccc; color: #666666; }
        """)
        self.disconnect_btn.setStyleSheet("""
            QPushButton {
                background-color: #f44336;
                color: white;
                padding: 10px;
                border: none;
                border-radius: 5px;
            }
            QPushButton:hover { background-color: #e53935; }
            QPushButton:disabled { background-color: #cccccc; color: #666666; }
        """)
        self.refresh_btn.setStyleSheet("""
            QPushButton {
                background-color: #2196F3;
                color: white;
                padding: 10px;
                border: none;
                border-radius: 5px;
            }
            QPushButton:hover { background-color: #1976D2; }
            QPushButton:disabled { background-color: #cccccc; color: #666666; }
        """)

        button_layout = QHBoxLayout()
        button_layout.addWidget(self.connect_btn)
        button_layout.addWidget(self.disconnect_btn)
        button_layout.addWidget(self.refresh_btn)
        button_layout.addWidget(self.browser_status_btn)
        button_layout.addWidget(self.recover_browser_btn)
        left_layout.addLayout(button_layout)

        main_layout.addWidget(left_panel)

        # 右侧数据显示
        self.data_list = QListWidget()
        self.data_list.setStyleSheet("QListWidget { font-size: 14px; background-color: #f0f0f0; border-radius: 5px; }")
        # 设置右侧数据列表的默认宽度为100像素
        # self.data_list.setFixedWidth(100)
        main_layout.addWidget(self.data_list)

        # 初始化数据处理模块
        # self.data_processor = DataProcessor()
        # self.data_processor.db_log_signal.connect(self.log)

    def log(self, message):
        """
        日志记录方法
        参数：
        - message: 要记录的日志信息
        """
        # 确保log_text已初始化
        if not hasattr(self, 'log_text'):
            self.log_text = QTextEdit(self)
            self.log_text.setReadOnly(True)
            self.log_text.setStyleSheet("QTextEdit { background-color: #ffffff; border: 1px solid #ccc; border-radius: 3px; padding: 5px; }")
        current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        self.log_text.append(f"{current_time} - {message}")

        # 自动清理日志，最多保留1000行
        if self.log_text.document().lineCount() > 10000:
            cursor = self.log_text.textCursor()
            cursor.movePosition(cursor.Start)
            cursor.movePosition(cursor.Down, cursor.KeepAnchor, 100)
            cursor.removeSelectedText()

    def _update_interval(self):
        """更新WebSocketWorker的间隔时间设置"""
        if hasattr(self, 'ws_worker') and self.ws_worker:
            try:
                interval_text = self.interval_input.text().strip()
                if interval_text and int(interval_text) > 0:
                    interval = int(interval_text)
                else:
                    interval = 0  # 默认值
            except ValueError:
                interval = 1  # 默认值

            self.ws_worker.rtv_interval = interval
            self.log(f"更新数据采集间隔时间为: {interval}秒")

    def start_websocket(self):
        # 先更新Token，确保使用最新的外部Token
        self.log("[启动流程] 开始更新Token...")
        self.update_token()
        
        # 获取更新后的token
        token = self.token_input.text()
        # 设置开始时间
        startTime=datetime.now()

        # 获取间隔时间 - 读取窗口文本，如果没有值则使用默认值10
        try:
            interval_text = self.interval_input.text().strip()
            if interval_text and int(interval_text) > 0:
                interval = int(interval_text)
            else:
                interval = 0  # 默认值
                self.log("使用默认间隔时间: {interval}秒")
        except ValueError:
            interval = 1  # 默认值
            self.log("间隔时间格式错误，使用默认值: {interval}秒")

        self.log(f"设置数据采集间隔时间为: {interval}秒")
        # 创建WebSocketWorker对象，传入token和间隔时间
        self.ws_worker = WebSocketWorker(token, interval)
        
        # 设置浏览器实例到WebSocketWorker（用于登录状态检查）
        browser = self.get_browser_instance()
        if browser:
            self.ws_worker.set_browser_instance(browser)
            self.log("[WebSocket] 浏览器实例已设置到Worker")
        else:
            self.log("[WebSocket] 警告：未找到浏览器实例，登录状态检查将不可用")
        
        # 设置SOC输入框引用到connection.py用于重订阅间隔
        if hasattr(self.ws_worker, 'set_soc_input'):
            self.ws_worker.set_soc_input(self.charging_soc_input)
        # 将WebSocketWorker对象的message_signal信号连接到handle_message槽函数
        self.ws_worker.message_signal.connect(self.handle_message)
        # 将WebSocketWorker对象的log_signal信号连接到log槽函数
        self.ws_worker.log_signal.connect(self.log)
        # 连接WebSocket连接成功信号
        self.ws_worker.connected_signal.connect(self.on_websocket_connected)
        # 连接WebSocket连接断开信号
        self.ws_worker.disconnected_signal.connect(self.on_websocket_disconnected)
        # 启动WebSocketWorker对象
        self.ws_worker.start()
        # 注意：按钮状态将在WebSocket实际连接成功后通过信号设置
        self.log("WebSocket已开始连接")
        # self.log("数据更新已开启")

    def on_websocket_connected(self):
        """WebSocket连接成功后的处理"""
        self.log("WebSocket连接成功，更新按钮状态")
        # 禁用连接按钮，启用断开按钮和刷新按钮
        self.connect_btn.setEnabled(False)
        self.disconnect_btn.setEnabled(True)
        self.refresh_btn.setEnabled(True)
        # 启动更新定时器
        self.update_timer.start(1000)

    def on_websocket_disconnected(self):
        """WebSocket连接断开后的处理"""
        self.log("WebSocket连接已断开，恢复按钮状态")
        # 恢复按钮状态
        self.connect_btn.setEnabled(True)
        self.disconnect_btn.setEnabled(False)
        self.refresh_btn.setEnabled(False)
        # 停止更新定时器
        self.update_timer.stop()

    def stop_websocket(self):
        # 停止更新定时器
        self.update_timer.stop()
        # 如果ws_worker存在，则停止ws_worker，并将ws_worker置为None
        if self.ws_worker:
            self.log("正在停止WebSocket连接...")
            self.ws_worker.stop()
            # 等待线程完全退出（最多等待5秒）
            if self.ws_worker.isRunning():
                self.ws_worker.wait(5000)  # 等待最多5秒
            self.ws_worker = None
            self.log("WebSocket连接已完全停止")
        # 设置连接按钮为可用状态
        self.connect_btn.setEnabled(True)
        # 设置断开连接按钮为不可用状态
        self.disconnect_btn.setEnabled(False)
        # 设置刷新按钮为不可用状态
        self.refresh_btn.setEnabled(False)
        gc.collect()
    def handle_message(self, data):
        # 获取消息中的函数类型
        func_type = data.get('func')
        # 如果函数类型为menu
        if func_type == "menu":
            # 更新设备树
            self.device_info = update_device_tree(self.device_tree, data, self.log)
        # 如果函数类型为rtv
        elif func_type == "rtv":
            # 遍历消息中的数据
            for item in data.get("data", []):
                self.latest_rtv_data[str(item.get("id"))] = item.get("value", "N/A")
            current_item = self.device_tree.currentItem()
            if current_item:
                level = get_item_level(current_item)
                rtv_ids = get_rtv_ids_for_item(current_item, level, self.device_tree, self.log)
                update_data_list_by_ids(self.data_list, rtv_ids, self.device_info, self.latest_rtv_data, self.log)

    def update_display(self):
        # 尝试更新显示
        try:
            # 获取当前选中的设备
            current_item = self.device_tree.currentItem()
            # 如果有选中的设备
            if current_item:
                # 获取设备等级
                level = get_item_level(current_item)
                # 获取设备的RTV ID
                rtv_ids = get_rtv_ids_for_item(current_item, level, self.device_tree, self.log)
                # 根据RTV ID更新数据列表
                update_data_list_by_ids(self.data_list, rtv_ids, self.device_info, self.latest_rtv_data, self.log)

            # 获取SOC值
            soc = float(self.latest_rtv_data.get('412001056', 0))
            # 获取运行模式
            runModel = self.latest_rtv_data.get('412001051', 0)
            # 获取充电开始时间
            charging_start = int(self.charging_time_input_start.text())
            # 获取充电结束时间
            charging_end = int(self.charging_time_input_end.text())
            # 获取放电开始时间
            discharging_start = int(self.discharging_time_input_start.text())
            # 获取放电结束时间
            discharging_end = int(self.discharging_time_input_end.text())
            # 获取充电SOC上限
            soc_upper = float(self.charging_soc_input.text())
            # 获取放电SOC下限
            soc_lower = float(self.discharging_soc_input.text())

            # 调用控制器进行充电放电监控
            self.controller.monitor_charge_discharge(
                soc, charging_start, charging_end,
                discharging_start, discharging_end,
                soc_upper, soc_lower, runModel
            )
        except Exception:
            # 如果发生异常，则忽略
            pass

    def refresh_data(self):
        # 手动刷新数据
        self.log("手动刷新数据...")
        # 如果ws_worker存在且websocket存在
        if self.ws_worker and self.ws_worker.websocket:
            # 清空latest_rtv_data
            # 清空device_info
            self.latest_rtv_data.clear()
            self.device_info.clear()
            # 停止websocket
            # self.stop_websocket()
            # self.start_websocket()
            self.ws_worker.request_refresh()
            self.log("已重新刷新WebSocket请求")

    def check_browser_status(self):
        """检查浏览器状态"""
        try:
            # 导入登录状态检查器
            from login_status_checker import LoginStatusChecker
            
            # 这里需要获取浏览器实例，假设从某个地方获取
            # 注意：实际使用时需要根据项目结构调整
            browser = self.get_browser_instance()
            
            if not browser:
                self.log("[浏览器检查] 未找到浏览器实例，请先启动浏览器")
                self.recover_browser_btn.setEnabled(False)
                return
            
            # 创建登录状态检查器
            checker = LoginStatusChecker(browser)
            
            # 执行完整检查
            self.log("[浏览器检查] 开始检查浏览器状态...")
            result = checker.check_login_status()
            
            if result['status'] == 'success':
                self.log(f"[浏览器检查] ✓ {result['message']}")
                self.recover_browser_btn.setEnabled(False)
            else:
                self.log(f"[浏览器检查] ✗ {result['message']}")
                self.recover_browser_btn.setEnabled(True)
                
        except Exception as e:
            self.log(f"[浏览器检查] 检查失败: {str(e)}")
            self.recover_browser_btn.setEnabled(True)

    def recover_browser(self):
        """恢复浏览器功能"""
        try:
            self.log("[浏览器恢复] 正在恢复浏览器...")
            
            # 使用浏览器管理器恢复浏览器
            if hasattr(self, 'browser_manager') and self.browser_manager:
                success = self.browser_manager.restart_browser()
                if success:
                    self.log("[浏览器恢复] ✓ 浏览器恢复成功")
                    # 更新WebSocketWorker中的浏览器实例
                    if hasattr(self, 'ws_worker') and self.ws_worker:
                        new_browser = self.browser_manager.get_browser()
                        if new_browser:
                            self.ws_worker.set_browser_instance(new_browser)
                            self.log("[浏览器恢复] WebSocketWorker已更新浏览器实例")
                else:
                    self.log("[浏览器恢复] ✗ 浏览器恢复失败")
            else:
                self.log("[浏览器恢复] 未找到浏览器管理器")
            
            # 延迟检查恢复结果
            import threading
            def delayed_check():
                import time
                time.sleep(5)  # 等待5秒
                self.check_browser_status()
            
            thread = threading.Thread(target=delayed_check)
            thread.daemon = True
            thread.start()
            
        except Exception as e:
            self.log(f"[浏览器恢复] 恢复失败: {str(e)}")

    def get_browser_instance(self):
        """获取浏览器实例"""
        try:
            # 首先尝试从浏览器管理器获取
            if hasattr(self, 'browser_manager') and self.browser_manager:
                browser = self.browser_manager.get_browser()
                if browser:
                    return browser
            
            # 备选：尝试从WebSocketWorker获取浏览器实例
            if hasattr(self, 'ws_worker') and self.ws_worker and hasattr(self.ws_worker, 'browser_instance'):
                return self.ws_worker.browser_instance
            else:
                return None
        except:
            return None

    def setup_browser_monitoring(self):
        """设置浏览器监控 - 可选的手动触发方式"""
        try:
            # 创建浏览器监控定时器
            self.browser_monitor_timer = QTimer()
            self.browser_monitor_timer.timeout.connect(self.check_browser_status)
            # 默认每小时检查一次浏览器状态
            self.browser_monitor_timer.start(3600000)  # 3600000毫秒 = 1小时
            
            self.log("[浏览器监控] 浏览器状态监控已启动")
        except Exception as e:
            self.log(f"[浏览器监控] 启动失败: {str(e)}")

    # 重写closeEvent方法，当窗口关闭时调用
    def closeEvent(self, event):
        gc.collect()
        # 停止websocket连接
        self.stop_websocket()
        # 接受关闭事件
        event.accept()
        # 关闭窗口
        self.close()
